package cn.itlight.basic.service.impl;

import cn.itlight.basic.constant.BaseConstants;
import cn.itlight.basic.exception.BusinessException;
import cn.itlight.basic.service.IVerifyCodeService;
import cn.itlight.basic.utils.StrUtils;
import cn.itlight.basic.utils.VerifyCodeUtils;
import cn.itlight.basic.vo.EmailRegisterVo;
import cn.itlight.basic.vo.LoginVo;
import cn.itlight.basic.vo.RegisterVo;
import cn.itlight.basic.vo.ShopVo;
import cn.itlight.user.domain.User;
import cn.itlight.user.domain.Wxuser;
import cn.itlight.user.mapper.UserMapper;
import cn.itlight.user.mapper.WxuserMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Service
public class VerifyCodeServiceImpl implements IVerifyCodeService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private WxuserMapper wxuserMapper;

    /*
    * @Title: getImageCode
    * @Description: 获取图形验证码
    * @Author: TomLiu
    * @Version: 1.0
    * @Date:  2022/7/7 8:42
    * @Parameters:
    * @Return
    */
    @Override
    public String getImageCode(String imageCodeKey) {

        if (StringUtils.isEmpty(imageCodeKey)){
            throw new BusinessException("参数不能为空，请重新填写参数！");
        }
        // 调用StrUtils的方法getComplexRandomString生成随机四位的字符串
        String code = StrUtils.getComplexRandomString(4);
        // 将字符串放在Redis中
        redisTemplate.opsForValue().set(imageCodeKey,code,5, TimeUnit.MINUTES);
        // 调用VerifyCodeUtils调用VerifyCode方法
        String resultObj = VerifyCodeUtils.VerifyCode(100, 35, code);

        return resultObj;
    }

    /*
    * @Title: smsCode
    * @Description: 发送短信验证码
    * @Author: TomLiu
    * @Version: 1.0
    * @Date:  2022/7/7 8:48
    * @Parameters:
    * @Return
    */
    @Override
    public void smsCode(RegisterVo registerVo) {

        // 手机号
        String phone = registerVo.getPhone();
        // 类型
        String type = registerVo.getType();

        // 参数非空判断
        if (StringUtils.isEmpty(type) || StringUtils.isEmpty(phone)){
            throw new BusinessException("参数不能为空，请重新填写");
        }
        // 判断类型
        if ("register".equals(type)){
            // 校验图形验证码是否正确
            checkImageCode(registerVo);
            //3.判断用户是否已注册，如果已注册提示用户
            User user = userMapper.loadByPhone(phone);

            if (user != null){
                throw new BusinessException("用户已注册，请直接登录，如果忘记密码，请点击忘记密码！");
            }
            sendCode(BaseConstants.VerifyCodeConstant.BUSINESS_REGISTER_PREFIX, phone);
        }else if ("binder".equals(type)){ // 2.2.微信绑定账号业务,发送短信验证码
            sendCode(BaseConstants.VerifyCodeConstant.BUSINESS_BINDER_PREFIX, phone);
        }


    }

    /**
     * @Title: checkImageCode
     * @Description: 校验图形验证码
     * @Author: Mr.She
     * @Version: 1.0
     * @Date:  2022/7/10 15:40
     * @Parameters: []
     * @Return void
     */
    public void checkImageCode(RegisterVo registerVo){
        // 图形验证码的key
        String imageCodeKey = registerVo.getImageCodeKey();
        // 图形验证码的value
        String imageCodeValue = registerVo.getImageCodeValue();
        //1.非空校验
        if (StringUtils.isEmpty(imageCodeKey) || StringUtils.isEmpty(imageCodeValue)){
            throw new BusinessException("参数不能为空！");
        }
        //2.判断图形验证码是否正确以及存在
        Object imageCodeValueTmp = redisTemplate.opsForValue().get(imageCodeKey);
        if (imageCodeValueTmp == null){
            throw new BusinessException("验证码已过期，请重新获取！");
        }
        // 忽略大小写比较图形验证码是否正确
        if (!imageCodeValueTmp.toString().equalsIgnoreCase(imageCodeValue)){
            throw new BusinessException("验证码错误，请重新输入！");
        }
    }

    /**
     * @Title: sendCode
     * @Description: 发送手机验证码
     * @Author: Mr.She
     * @Version: 1.0
     * @Date:  2022/7/10 15:39
     * @Parameters: [businessKey, phone]
     * @Return void
     */
    public void sendCode(String businessKey, String phone){
        //4.根据电话号码拼接业务键，去redis中获取对应的value值，判断是否存在
        String phoneCodeKey = businessKey + phone;
        Object phoneCodeValue = redisTemplate.opsForValue().get(phoneCodeKey);
        //0.定义一个空字符串，专门用来接收验证码
        String phoneCode = "";
        if (phoneCodeValue == null){//1.不存在
            //1.生成新的随机验证码,并赋值给空字符串
            phoneCode = StrUtils.getComplexRandomString(4);
        }else {//2.存在
            //1.分割value得到时间戳，跟现在的时间戳做减法，如果小于1分钟的毫秒数抛出异常
            String[] phoneCodeValueTmp = phoneCodeValue.toString().split(":");
            // 之前存入code时，我们记录的时间戳
            Long oldTime = Long.valueOf(phoneCodeValueTmp[0]);
            // 现在的时间戳
            Long nowTime = System.currentTimeMillis();
            if (nowTime - oldTime < 1*60*1000){
                throw new BusinessException("请一分钟之后再获取！");
            }
            //2.将旧的验证码赋值给空字符串
            phoneCode = phoneCodeValueTmp[1];
        }
        //5.通过业务键+phone作为key，验证码+时间戳作为value，存入redis，设置为三分钟有效
        String phoneCodeRedis = System.currentTimeMillis() + ":" + phoneCode;
        redisTemplate.opsForValue().set(phoneCodeKey, phoneCodeRedis, 3, TimeUnit.MINUTES);
        //6.发送短信验证码
        // SmsUtils.sendCode(phone, "亲，您的验证码是："+ phoneCode);
        System.out.println("亲，您的验证码是："+ phoneCode);
    }

    @Override
    public void emailCode(EmailRegisterVo emailRegisterVo) {
        // 图形验证码
        String imageCodeValueEmail = emailRegisterVo.getImageCodeValueEmail();
        // 邮箱
        String email = emailRegisterVo.getEmail();
        // 图形验证码的key值
        String imageCodeKeyEmail = emailRegisterVo.getImageCodeKeyEmail();
        // 参数非空判断
        if (StringUtils.isEmpty(imageCodeValueEmail)
                || StringUtils.isEmpty(email)
                || StringUtils.isEmpty(imageCodeKeyEmail)){
            throw new BusinessException("参数不能为空，请重新填写");
        }
        // 根据key值判断redis之前是否存在或者过期
        Object imageCodeTmp = redisTemplate.opsForValue().get(imageCodeKeyEmail);
        // 为空则不存在或者过期
        if (imageCodeTmp == null) {
            throw new BusinessException("验证码已过期，请重新获取！");
        }
        // 忽略大小写比较图形验证码是否正确
        if (!imageCodeTmp.toString().equalsIgnoreCase(imageCodeValueEmail)){
            throw new BusinessException("验证码错误，请重新输入！");
        }
        // 根据邮箱查用户
        User user = userMapper.loadByEmail(email);
        // 判断之前是否存在
        if (user != null){
            throw new BusinessException("此用户已存在，请直接登录");
        }
        // 到此说明用户真的需要验证码
        // 根据电话号码拼接业务键，去redis中获取对应的value值，判断是否存在
        String emailCodeKey = BaseConstants.VerifyCodeConstant.BUSINESS_REGISTER_PREFIX + email;
        Object emailCodeValueTmp = redisTemplate.opsForValue().get(emailCodeKey);
        String emailCode = "";
        if (emailCodeValueTmp == null){
            // 如果为空直接生成新的
            emailCode = StrUtils.getComplexRandomString(4);
        } else {
            // 不为空就要获取时间戳做对比看是否超过一分钟
            String[] split = emailCodeValueTmp.toString().split(":");
            Long OldTime = Long.valueOf(split[0]);
            Long nowTime = System.currentTimeMillis();
            if (nowTime - OldTime <= 1 * 60 * 1000){
                throw new BusinessException("请求太过频繁，一分钟后才能重新发送");
            }
            // 将旧的验证码赋值给空字符串
            emailCode = split[1];
        }
        //5.通过业务键+phone作为key，验证码+时间戳作为value，存入redis，设置为三分钟有效
        String emailCodeRedis = System.currentTimeMillis() + ":" + emailCode;
        redisTemplate.opsForValue().set(emailCodeKey, emailCodeRedis, 3, TimeUnit.MINUTES);
        //6.发送短信验证码
        // SmsUtils.sendCode(phone, "亲，您的验证码是："+ smsCode);
        System.out.println("亲，您的验证码是："+ emailCode);
    }

    /*
    * @Title: loginCode
    * @Description: 手机登录验证码
    * @Author: TomLiu
    * @Version: 1.0
    * @Date:  2022/7/9 17:49
    * @Parameters:
    * @Return
    */
    @Override
    public void loginCode(LoginVo loginVo) {
        String username = loginVo.getUsername();
        // 参数非空判断
        if (StringUtils.isEmpty(username)){
            throw new BusinessException("参数不能为空，请重新填写");
        }
        // 根据手机查用户
        User user = userMapper.loadByPhone(username);
        // 判断之前是否存在
        if (user == null){
            throw new BusinessException("此用户不存在");
        }
        // 到此说明用户真的需要验证码
        // 根据电话号码拼接业务键，去redis中获取对应的value值，判断是否存在
        String emailCodeKey = BaseConstants.VerifyCodeConstant.BUSINESS_REGISTER_PREFIX + username;
        Object emailCodeValueTmp = redisTemplate.opsForValue().get(emailCodeKey);
        String emailCode = "";
        if (emailCodeValueTmp == null){
            // 如果为空直接生成新的
            emailCode = StrUtils.getComplexRandomString(4);
        } else {
            // 不为空就要获取时间戳做对比看是否超过一分钟
            String[] split = emailCodeValueTmp.toString().split(":");
            Long OldTime = Long.valueOf(split[0]);
            Long nowTime = System.currentTimeMillis();
            if (nowTime - OldTime <= 1 * 60 * 1000){
                throw new BusinessException("请求太过频繁，一分钟后才能重新发送");
            }
            // 将旧的验证码赋值给空字符串
            emailCode = split[1];
        }
        //5.通过业务键+phone作为key，验证码+时间戳作为value，存入redis，设置为三分钟有效
        String emailCodeRedis = System.currentTimeMillis() + ":" + emailCode;
        redisTemplate.opsForValue().set(emailCodeKey, emailCodeRedis, 3, TimeUnit.MINUTES);
        //6.发送短信验证码
        // SmsUtils.sendCode(phone, "亲，您的验证码是："+ smsCode);
        System.out.println("您的登录验证码是："+ emailCode);
    }

    @Override
    public void shopCode(ShopVo shopVo) {
        String username = shopVo.getPhone();
        // 参数非空判断
        if (StringUtils.isEmpty(username)){
            throw new BusinessException("参数不能为空，请重新填写");
        }
        // 到此说明用户真的需要验证码
        // 根据电话号码拼接业务键，去redis中获取对应的value值，判断是否存在
        String emailCodeKey = BaseConstants.VerifyCodeConstant.BUSINESS_REGISTER_PREFIX + username;
        Object emailCodeValueTmp = redisTemplate.opsForValue().get(emailCodeKey);
        String emailCode = "";
        if (emailCodeValueTmp == null){
            // 如果为空直接生成新的
            emailCode = StrUtils.getComplexRandomString(4);
        } else {
            // 不为空就要获取时间戳做对比看是否超过一分钟
            String[] split = emailCodeValueTmp.toString().split(":");
            Long OldTime = Long.valueOf(split[0]);
            Long nowTime = System.currentTimeMillis();
            if (nowTime - OldTime <= 1 * 60 * 1000){
                throw new BusinessException("请求太过频繁，一分钟后才能重新发送");
            }
            // 将旧的验证码赋值给空字符串
            emailCode = split[1];
        }
        //5.通过业务键+phone作为key，验证码+时间戳作为value，存入redis，设置为三分钟有效
        String emailCodeRedis = System.currentTimeMillis() + ":" + emailCode;
        redisTemplate.opsForValue().set(emailCodeKey, emailCodeRedis, 3, TimeUnit.MINUTES);
        //6.发送短信验证码
        // SmsUtils.sendCode(phone, "亲，您的验证码是："+ smsCode);
        System.out.println("您的登录验证码是："+ emailCode);
    }
}
